#from reader import GoogleReader
#import random
#import urllib
#import twitter
#import tinyurl
#from const import CONST

from api import Twitter
from api import TwitterError
from userconfig import USER
import time
import re
import cPickle as p
import traceback
import WConio

COLLECT_TIMES = 12
COLLECT_SLEEP = 300
CURRENT_USER = 'junytang'

FOLLOW_EXPIRATION = 259200 # 3 day
FOLLOW_PPL_LIMIT = 3

RET_FAILED = -1
RET_TRUE = 0
RET_FALSE = 1

class AFError(Exception):
  '''Base class for errors'''

class AutoFollow(object):

    def __init__ (self, username, password):
        #self.Twitter = Twitter(token=self.LoadMap('access_token'))
        self.Twitter_auth = Twitter(email="junytang@gmail.com",password="qazwsx",domain="api.fanfou.com",protocol="http")
        self.Twitter_none = Twitter(email="junytang@gmail.com",password="qazwsx",domain="api.fanfou.com",protocol="http")
        
    def CreateMap(self,filename,object,verbose=1):
        try:
            if verbose == 1: print "Creating map file %s... " % (filename),
            f = open(filename,'w')
            p.dump(object,f)
            f.close()
            if verbose == 1: print "\t\t\t\t [ OK ]"
            return RET_TRUE
        except Exception,e:
            if verbose == 1: print "\t\t\t\t[ FAIL ]"
            return RET_FALSE
    
    def LoadMap(self,filename,islist=1):
        if islist == 1:obj = []
        else: obj = {}
        try:
            print "Loading map file %s... " % (filename),
            f = open(filename)
            obj = p.load(f)
            f.close()
            print "\t\t\t\t [ OK ]"
        except Exception,e:
            print "\t\t\t\t[ FAIL ]"
        return obj
    
    def LoadKeywords(self,filename):
        keys = [];
        try:
            print "Loading keywords file %s... " % (filename),
            f = open(filename, 'r')
            keys = f.readlines()
            f.close()
            print "\t\t\t [ OK ]"
        except Exception,e:
            print "\t\t\t[ FAIL ]"
        return keys         

    def ErrorProcess(self, err):
        print "-------- Twitter Error --------"
        print "Code: %d" % (err.code)
        print "Error: %s" % (err.msg)
        #print "Next API reset time is %s" % (self.GetApiResetTime())
        print "-------------------------------"
        time.sleep(COLLECT_SLEEP)

    def GetApiLimit(self):
        rate = self.Twitter_none.account.rate_limit_status()
        return 100 - rate['remaining_hits']

    def GetApiResetTime(self):
        rate = self.Twitter_none.account.rate_limit_status()
        return time.strftime("%H:%M:%S",time.localtime(rate['reset_time_in_seconds']))

    def GetUserInfo(self,user):
        try:
            following = 0
            followers = 0
            utc_offset = 0
            u = self.Twitter_none.users.show(id=user)
            if u['friends_count']: following = u['friends_count']
            else:  following = 0
            if u['followers_count']: followers = u['followers_count']
            else:  followers = 0
            if u['utc_offset']: utc_offset = u['utc_offset']
            else:  utc_offset = 0
            return (following,followers,utc_offset)
        except TwitterError,e:
            self.ErrorProcess(e)
            return (0,0,0)          
        except Exception,e:
            print e
            return (0,0,0)
          
    def IsFollow(self,user_a, user_b):
        try:
            if self.Twitter_auth.friendships.exists(user_a=user_a,user_b=user_b) == True:
                return RET_TRUE
            else:
                return RET_FALSE
        except TwitterError,e:
            self.ErrorProcess(e)
            return RET_FAILED
        except Exception,e:
            print e
            return RET_FAILED
            
    def Follow(self,user):
        try:
            if self.Twitter_auth.friendships.exists(user_a=CURRENT_USER,user_b=user) == False:
                self.Twitter_auth.friendships.create(id=user)
                return RET_TRUE;
            else: return RET_FALSE
        except TwitterError,e:
            self.ErrorProcess(e)
            return RET_FAILED
        except Exception,e:
            print e    
            return RET_FAILED

    def UnFollow(self,user):
        try:
            if self.Twitter_auth.friendships.exists(user_a=CURRENT_USER,user_b=user) == True:
                self.Twitter_auth.friendships.destroy(id=user)
                return RET_TRUE
            else:
                return RET_FALSE
        except TwitterError,e:
            self.ErrorProcess(e)
            return RET_FAILED
        except Exception,e:
            print e    
            return RET_FAILED

    def MeetRequirement(self,user):
        (following, followers, utc_offset) = self.GetUserInfo(user)
        print "Checking %s: %d %d %d" % (user.decode('utf-8'), following, followers, utc_offset)

        if followers >= 20 and following >=20 and utc_offset == 28800:
            return RET_TRUE
        else:
            return RET_FALSE

    def GetPublicPosts(self):
        apilimit = 0
        print "Retrieving posts..."
        publicposts = self.LoadMap('publicposts_fan.map')
        print "Creating map...",
        for i in range(COLLECT_TIMES):
            try:
                if (i % 5 == 0): apilimit = 0#self.GetApiLimit()
                posts = self.Twitter_none.statuses.public_timeline()
                for s in posts:
                    if 'user' in s: #unicode(s['user']['id']).encode('utf-8')
                        publicposts.append({'user': (s['user']['id']).encode('utf-8'),'text': s['text'].encode('utf-8')})
                        self.CreateMap('publicposts_fan.map', publicposts,0)
                print "%3d%% API:%3d%%" % ( (i+1) * 100 / COLLECT_TIMES, apilimit),
                print "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                time.sleep(COLLECT_SLEEP)
            except TwitterError,e:
                print "\t\t\t\t\t\t[ FAIL ]"
                self.ErrorProcess(e)
                print "Creating map...",
                continue
            except Exception,e:
                print "\t\t\t\t\t\t[ FAIL ]"
                print e
                #exstr = traceback.format_exc()  
                #print exstr
                time.sleep(COLLECT_SLEEP)
                print "Creating map...",
                continue
        print "\t\t\t\t\t\t [ OK ]"     
        return publicposts  

    def CheckUsers(self):
        print "Checking users..."
        whiteusers = {};
        tmpusers = self.LoadMap('whiteusers_fan.map',0)
        blackusers = self.LoadMap('blackusers_fan.map',0)
        curtime = time.mktime(time.localtime())
        old_setting = WConio.gettextinfo()[4] & 0x00FF
        WConio.textattr(WConio.LIGHTRED)
        for u,t in tmpusers.items():
            whiteusers[u] = t
            if(curtime >= t + FOLLOW_EXPIRATION):
                ret = self.IsFollow(u,CURRENT_USER)
                if ret == RET_TRUE:
                    print "Remove (followed): %s" % (u.decode('utf-8'))
                    del whiteusers[u]
                elif ret == RET_FALSE:
                    print "Remove (unfollowed): %s" % (u.decode('utf-8'))
                    del whiteusers[u]
                    self.UnFollow(u)
                    if (u in blackusers) == True:
                        blackusers[u] = blackusers[u] + 1
                    else:  
                        blackusers[u] = 1
                else:
                    print "Remove (not exist): %s" % (u.decode('utf-8'))
                    del whiteusers[u]
                    
        WConio.textattr(old_setting)                    
        self.CreateMap('whiteusers_fan.map',whiteusers)
        self.CreateMap('blackusers_fan.map',blackusers)

    def TestUsers(self):
        whiteusers = self.LoadMap('whiteusers_fan.map',0)
        curtime = time.mktime(time.localtime())
        for u,t in whiteusers.items():
            print u, self.IsFollow(u,CURRENT_USER)

    def Start(self):
        temp = {}
        whiteusers = self.LoadMap('whiteusers_fan.map',0)
        blackusers = self.LoadMap('blackusers_fan.map',0)
        whitewords = self.LoadKeywords('whitewords.txt')
        blackwords = self.LoadKeywords('blackwords.txt')
        publicposts = self.GetPublicPosts()
        
        for t in publicposts:
            bfound = False

            for b in blackwords:
                if re.search(r'\b'+ b.strip('\n') + r'\b',t['text'],re.I|re.U):
                    bfound = True
                    break

            if bfound == False:
                for w in whitewords:
                    if re.search(r'\b'+ w.strip('\n') + r'\b',t['text'],re.I|re.U):
                        bfound = True
                        temp[t['user']] = time.mktime(time.localtime())  
                        break
        count = 0;
        for u,t in temp.items():
            if count >= FOLLOW_PPL_LIMIT: break
            if (u in blackusers) == True:
                old_setting = WConio.gettextinfo()[4] & 0x00FF
                WConio.textattr(WConio.YELLOW)
                print "In blacklist: %s" % (u.decode('utf-8'))
                WConio.textattr(old_setting)
                if blackusers[u] >= 3:
                    print "skip: %s" % (u.decode('utf-8'))
                    continue
            if self.MeetRequirement(u) == RET_TRUE:
                if self.Follow(u) == RET_TRUE:
                    whiteusers[u] = t
                    old_setting = WConio.gettextinfo()[4] & 0x00FF
                    WConio.textattr(WConio.LIGHTGREEN)
                    print "Follow: %s" % (u.decode('utf-8'))
                    WConio.textattr(old_setting)
                    count = count +1
                else:
                    print "You have followed %s or you have been blocked" % (u.decode('utf-8'))
            else:
                print "User: %s can not meet your requirement" % (u.decode('utf-8'))

        print "Followed %d users" % ( count ) 
        print "Cleared posts..." 

        self.CreateMap('whiteusers_fan.map',whiteusers)
        self.CreateMap('publicposts_fan.map', [])

    def Test(self):
        whiteusers = self.LoadMap('whiteusers_fan.map',0)
        for u,t in whiteusers.items():
            print u

def main():

    af = AutoFollow(USER.twuser,USER.twpass)

    while True:
        af.CheckUsers()
        af.Start()

    #try:
    #    print af.Twitter.account.verify_credentials()
    #except TwitterError,e:
    #    af.ErrorProcess(e)

    #af.CheckUsers()
    #af.GetPublicPosts()
    #af.TestUsers()
    #print af.Follow('junytangrob')
    #print time.mktime(time.localtime()) + 259200
    
if __name__=='__main__' :
    main()
